package simulation;

import javafx.animation.AnimationTimer;
import javafx.scene.control.*;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;

import java.util.EnumMap;

public class Controller {
    public TextField textNum;

    public Button btnStart;
    public Button btnPause;
    public Button btnReset;

    public Slider speedSlider;
    public Slider recoverySlider;
    public Slider rateSlider;

    public Pane chart;
    public Pane histogram;

    public Label dayLabel;
    public Label healthyLabel;
    public Label infectedLabel;
    public Label symptomaticLabel;

    private int num = 1000;

    private Movement clock;
    private final EnumMap<State, Rectangle> hrects = new EnumMap<>(State.class);

    private class Movement extends AnimationTimer {

//        private final long INTERVAL = 10000000000L / GlobalVar.FRAMES_PER_SEC;
        private final long INTERVAL = 1000000000L / GlobalVar.FRAMES_PER_SEC;

        private long last = 0;
        private long ticks = 0;


        @Override
        public void handle(long now) {
            if (now - last > INTERVAL / GlobalVar.PLAYBACK_SPEED) {
                simulation.Main.step();
                drawCharts();
                last = now;
                ticks++;
                GlobalVar.TIME++;
                if (ticks == 1000)
                    ticks = 0;
            }
        }

        public long getTicks() {
            return ticks;
        }
    }

    public void initialize() {
        speedSlider.valueProperty().addListener((observableValue, number, t1) -> GlobalVar.PLAYBACK_SPEED = number.intValue());
        rateSlider.valueProperty().addListener((observableValue, number, t1) -> {
            double rate = number.doubleValue() / 100;
            if (rate < 0.001)
                rate = 0;
            GlobalVar.INFECTION_RATE = rate;
        });
        recoverySlider.valueProperty().addListener(((observableValue, number, t1) -> GlobalVar.DAYS_TO_RECOVER = number.doubleValue()));
        clock = new Movement();
        disableButtons(false, false, true);
    }

    public void resetButtonClicked() {
        clock = new Movement();
        if (textNum.getText().isEmpty()) {
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setTitle("警告");
            alert.setHeaderText("人数不能为空！");
            alert.showAndWait();
        }
        else {
            try {
                clock.stop();
                num = Integer.parseInt(textNum.getText());

                if (num < 1 || num > 5000) {
                    Alert alert = new Alert(Alert.AlertType.WARNING);
                    alert.setTitle("警告");
                    alert.setHeaderText("请注意人数取值范围！");
                    alert.showAndWait();
                }
                simulation.Main.setNum(num);
                disableButtons(false, false, true);
                histogram.getChildren().clear();
                chart.getChildren().clear();

                // reset time
                GlobalVar.TIME = 0;
            }
            catch (NumberFormatException e) {
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setTitle("错误");
                alert.setHeaderText("输入不合法！");
                alert.showAndWait();
            }
        }
    }

    public void startButtonClicked() {
        recoverySlider.setDisable(true);
        resetGraph();
        drawCharts();
        clock.start();
        disableButtons(true, true, false);
    }

    public void pauseButtonClicked() {
        recoverySlider.setDisable(false);
        clock.stop();
        disableButtons(false, false, true);
    }

    private void disableButtons(boolean reset, boolean start, boolean pause) {
        btnReset.setDisable(reset);
        btnStart.setDisable(start);
        btnPause.setDisable(pause);
    }

    public void resetGraph() {
        int offset = 0;
        for (State s : State.values()) {
            Rectangle r = new Rectangle(60, 0, Student.getColor(s));
            r.setTranslateX(offset);
            offset += 65;
            hrects.put(s, r);
            histogram.getChildren().add(r);
        }
    }

    public void drawCharts() {
        // update days
        dayLabel.setText("第" + GlobalVar.TIME / 2000 + "天");

        EnumMap<State, Integer> currentPop = simulation.Main.getCurrPop();
        healthyLabel.setText("健康：" + (currentPop.getOrDefault(State.HEALTHY, 0)) + "人");
        infectedLabel.setText("感染：" + currentPop.getOrDefault(State.INFECTED, 0) + "人");
        symptomaticLabel.setText("发病：" + currentPop.getOrDefault(State.SYMPTOMATIC, 0) + "人");
        for (State s : hrects.keySet()) {
            if (currentPop.containsKey(s)) {
                hrects.get(s).setVisible(true);
                hrects.get(s).setHeight((double)currentPop.get(s) * 500  / num);
                hrects.get(s).setTranslateY(500 - hrects.get(s).getHeight());

                if (clock.getTicks() == 0)
                    chart.getChildren().clear();
                Circle c = new Circle(1, Student.getColor(s));
                c.setTranslateX(clock.getTicks() / 5.0);
                c.setTranslateY(200 - currentPop.get(s) * 190 / (double)num);
                chart.getChildren().add(c);
            }
            else {
                hrects.get(s).setVisible(false);
            }
        }
    }
}
